﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Zhang.SQLServer
{
    public class BaseMapper
    {
        /// <summary>
        /// SQL执行
        /// </summary>
        protected static readonly SQLHelper SqlHelper = new SQLHelper();
        /// <summary>
        /// 增加修改基类
        /// </summary>
        /// <param name="model">规范实体类</param>
        /// <param name="typeEnum"></param>
        /// <param name="tName">表名,如果实体类名称和数据库表名一致 则不需要填写</param>
        /// <returns></returns>
        protected static OperateParam GetCmdText(object model, SqlTypeEnum typeEnum,string tName = "")
        {
            var entity = new OperateParam {LstParam = new List<SqlParameter>()};
            var sFields = string.Empty;
            var sParams = string.Empty;
            var id = string.Empty;
            var type = model.GetType();
            var tableName = type.Name;
            if (!string.IsNullOrEmpty(tName))
            {
                tableName = tName;
            }
            foreach (var item in type.GetProperties())
            {
                var name = item.Name;
                var value = item.GetValue(model, null);
                if (name == "ID")
                {

                    id = value == null ? "" : value.ToString();
                    continue;
                }
                if (value == null)
                {
                    continue;
                }
                entity.LstParam.Add(new SqlParameter("@" + name, value));
                switch (typeEnum)
                {
                    case SqlTypeEnum.Add:
                        sFields += "[" + name + "],";
                        sParams += "@" + name + ",";
                        break;
                    case SqlTypeEnum.Update:
                        sFields += "[" + name + "]=@" + name + ",";
                        break;
                    default:
                        throw new ArgumentOutOfRangeException(nameof(typeEnum), typeEnum, null);
                }
            }
            switch (typeEnum)
            {
                case SqlTypeEnum.Add:
                    entity.Sql = "INSERT INTO " + tableName + "(" + sFields.TrimEnd(',') + ") VALUES (" +
                                 sParams.TrimEnd(',') + ") SELECT CAST(scope_identity() AS INT) AS ID";
                    return entity;
                case SqlTypeEnum.Update:
                    entity.Sql = $"UPDATE {tableName} SET {sFields.TrimEnd(',')} WHERE ID = {id}";
                    return entity;
                default:
                    return new OperateParam();
            }
        }

        /// <summary>
        /// 把IDataReader反射成实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dataReader"></param>
        /// <param name="dic"></param>
        /// <returns></returns>
        protected List<T> BindData<T>(IDataReader dataReader, Dictionary<string, string> dic = null) where T : class, new()
        {
            var result = new List<T>();
            Type tt = typeof(T);

            while (dataReader.Read())
            {
                object newitem = Activator.CreateInstance(tt);

                for (int i = 0; i < dataReader.FieldCount; i++)
                {
                    var fname = dataReader.GetName(i);
                    if (dic != null && dic.ContainsKey(fname))
                    {
                        fname = dic[fname];
                    }
                    foreach (var item in tt.GetProperties())
                    {
                        if (item.Name.ToLower() == fname.ToLower())
                        {
                            object val = dataReader[i];

                            if (!item.PropertyType.IsValueType && val == null)
                                break;

                            if (dataReader[i] == DBNull.Value)
                                break;

                            if (dataReader[i] is int || dataReader[i] is int)
                                val = Convert.ToInt32(dataReader[i]);

                            if (item.PropertyType == typeof(string))
                                val = dataReader[i].ToString();
                            item.SetValue(newitem, val, null);
                            break;
                        }
                    }
                }
                result.Add((T)newitem);
            }

            return result;
        }

        /// <summary>
        /// 把DataRow对象转成实体类。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <returns></returns>
        protected static T ToEntity<T>(DataRow dr) where T : new()
        {
            if (dr == null)
                return default(T);
            //T t = Activator.CreateInstance<T>();
            T t = new T();
            PropertyInfo[] propertys = t.GetType().GetProperties();
            DataColumnCollection Columns = dr.Table.Columns;
            foreach (PropertyInfo property in propertys)
            {
                if (!property.CanWrite)
                    continue;
                string columnName = property.Name;
                if (Columns.Contains(columnName))
                {
                    object value = dr[columnName];
                    if (value is DBNull)
                        continue;
                    try
                    {
                        //property.SetValue(t, Convert.ChangeType(value, property.PropertyType), null);
                        property.SetValue(t, value, null);
                    }
                    catch
                    {
                        continue;
                    }
                }
            }
            return t;
        }

        /// <summary>
        /// 把DataTable对象转成实体类的列表。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        protected static List<T> ToEntityList<T>(DataTable dt) where T : new()
        {
            List<T> list = new List<T>();
            if (dt != null && dt.Rows.Count > 0)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    list.Add(ToEntity<T>(dr));
                }
            }
            return list;
        }

        /// <summary>
        /// 把IDataReader对象转成实体类。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <returns></returns>
        protected static T ToEntity<T>(IDataReader dr) where T : new()
        {
            if (dr != null && dr.Read())
            {
                return DataReaderToEntity<T>(dr);
            }
            return default(T);
        }

        /// <summary>
        /// 把IDataReader对象转成实体类的列表。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr"></param>
        /// <returns></returns>
        protected static List<T> ToEntityList<T>(IDataReader dr) where T : new()
        {
            List<T> list = new List<T>();
            if (dr == null) return list;
            while (dr.Read())
            {
                list.Add(DataReaderToEntity<T>(dr));
            }
            return list;
        }

        /// <summary>
        /// 把IDataReader对象转成实体类。 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dr">需要参数的方法dr.Read()返回值为true。</param>
        /// <returns></returns>
        private static T DataReaderToEntity<T>(IDataReader dr) where T : new()
        {
            T t = new T();
            PropertyInfo[] propertys = t.GetType().GetProperties();
            List<string> fieldNameList = new List<string>();
            for (int i = 0; i < dr.FieldCount; i++)
            {
                fieldNameList.Add(dr.GetName(i));
            }
            foreach (PropertyInfo property in propertys)
            {
                if (!property.CanWrite)
                    continue;
                string fieldName = property.Name;
                if (fieldNameList.Contains(fieldName))
                {
                    object value = dr[fieldName];
                    if (value is DBNull)
                        continue;
                    try
                    {
                        if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            var typeArray = property.PropertyType.GetGenericArguments();
                            var baseType = typeArray[0];

                            if (baseType.IsEnum) //属性类型是否表示枚举
                            {
                                var enumName = Enum.ToObject(baseType, value.ToInt());
                                property.SetValue(t, enumName, null); //获取枚举值，设置属性值
                            }
                            else
                            {
                                property.SetValue(t, value, null);
                            }
                        }
                        else
                        {
                            if (property.PropertyType.IsEnum) //属性类型是否表示枚举
                            {
                                var enumName = Enum.ToObject(property.PropertyType, value.ToInt());
                                property.SetValue(t, enumName, null); //获取枚举值，设置属性值
                            }
                            else
                            {
                                property.SetValue(t, value, null);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        try
                        {
                            var str = property.PropertyType.Name.ToUpper();
                            if (property.PropertyType.IsGenericType &&
                                property.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                            {
                                var typeArray = property.PropertyType.GetGenericArguments();
                                var baseType = typeArray[0];
                                str = baseType.Name.ToUpper();
                            }

                            switch (str)
                            {
                                case "INT32":
                                    property.SetValue(t, value.ToInt(), null);
                                    break;
                                case "DECIMAL":
                                    property.SetValue(t, value.ToDecimal(), null);
                                    break;
                            }
                        }
                        catch
                        {
                            continue;
                        }
                    }
                }
            }
            return t;
        }


        /// <summary>
        /// 判断实体类内的属性是否都为空
        /// </summary>
        /// <param name="obj"></param>
        /// <returns>true=都为空，false=不是都为空</returns>
        protected static bool IsPropNull(object obj)
        {
            var t = obj.GetType();
            var props = t.GetProperties();
            foreach (var item in props)
            {
                //排除主键id
                if (item.Name.ToLower() == "id") { continue; }
                //一旦有不为null的值，就返回false
                if (item.GetValue(obj) != null)
                {
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        protected enum SqlTypeEnum
        {
            /// <summary>
            /// 
            /// </summary>
            Add,
            /// <summary>
            /// 
            /// </summary>
            Update
        }
    }
}
